package com.benew.ntt.ydeval.view

import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.PixelFormat
import android.os.Build
import android.os.Looper
import android.provider.Settings
import android.text.SpannableStringBuilder
import android.util.Log
import android.view.View
import android.view.WindowManager
import com.benew.ntt.evaluate.BuildConfig
import com.benew.ntt.evaluate.EvalScore
import com.benew.ntt.evaluate.constant.EvalError
import com.benew.ntt.evaluate.constant.EvalStatus
import com.benew.ntt.evaluate.constant.EvalType
import com.benew.ntt.evaluate.sdk.IEvalSDKListener
import com.benew.ntt.ydeval.view.wiget.EvalView
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.StringUtils
import com.ntt.core.nlogger.NLogger
import com.benew.ntt.evaluate.sdk.EvalSDK
import com.benew.ntt.evaluate.sdk.EvalSDKEntity
import com.benew.ntt.player.AudioItem
import com.benew.ntt.player.IAudioPlayListener
import com.benew.ntt.player.NttPlayCtrl
import com.benew.ntt.player.SourceType
import com.benew.ntt.ydeval.YDResultParse
import com.benew.ntt.ydeval.listener.IEvalListener
import com.blankj.utilcode.util.ToastUtils
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

/**
 * Created by Android Studio.
 * User: tw
 * Date: 2022/1/4
 * Time: 4:41 下午
 * 口语评测管理器
 */
@SuppressLint("StaticFieldLeak")
object EvalManager : View.OnAttachStateChangeListener {
    private val TAG = javaClass.simpleName

    private var mContext: Context? = null

    private var mEvalView: EvalView? = null
    private var mWindowManager: WindowManager? = null
    private lateinit var mWindowLayoutParams: WindowManager.LayoutParams

    //录音位置
    private var mRecordPath: String? = null

    //评测监听
    private var mEvalListeners = mutableSetOf<IEvalListener>()

    //评测状态
    private var mEvalStatus = EvalStatus.UNKNOW

    fun getEvalStatus() = this.mEvalStatus

    fun init(context: Context) {
        mContext = context
        initLayoutParams()
        NttPlayCtrl.init(context)
        EvalSDK.init(context)
    }

    fun registerEvalListener(evalListener: IEvalListener) {
        mEvalListeners.add(evalListener)
    }

    fun unRegisterEvalListener(evalListener: IEvalListener) {
        mEvalListeners.remove(evalListener)
    }

    /**
     * 在调用开始录音前需要先实现 IEvaluationListener 接口
     *
     * @param entity 需要评测的内容
     */
    @OptIn(ExperimentalStdlibApi::class)
    fun startEval(entity: EvalEntity?) {
        NLogger.d(TAG, "调用开始评测 startEval")

        if (
            entity == null
            || StringUtils.isEmpty(entity.content)
            || StringUtils.isEmpty(entity.type)
        ) {
            ToastUtils.showShort("请检查评测的内容或者类型是否正常！")
            return
        }
        entity.content = entity.content!!.trim()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mContext?.let {
                if (!Settings.canDrawOverlays(it)) {
                    val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
                    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                    it.startActivity(intent)
                    return
                }
            }
        }
        EvalSDK.registerEvalListener(mEvalSDKListener)

        cancelAll()
        //获取当前用户设置的难易度
        GlobalScope.launch {
            EvalScore.getScore()
            YDResultParse.setupIndex(entity.content, entity.type, YDResultParse.mIndexMap)
        }
        mEvalHandler.mAutoClose = entity.autoClose
        if (entity.beforeOrigin && !entity.audioUrl.isNullOrBlank()) {
            mEvalHandler.sendBeforeOrigin(entity)
        } else {
            EvalSDK.startEval(entity)
        }
    }

    private val mEvalSDKListener = object : IEvalSDKListener {

        override fun onStartEval(evalSDKEntity: EvalSDKEntity) {
            mEvalHandler.sendStopCloseCountDown()

            show(evalSDKEntity as EvalEntity, false)
        }

        override fun onStartRecord() {
            mEvalHandler.sendStopCloseCountDown()

            mEvalView?.startRecord()
        }

        override fun onError(errorMsg: String?, code: Int) {
            mEvalHandler.sendStopCloseCountDown()

            mEvalView?.showError(errorMsg)
        }

        override fun onProgress(msg: String?) {
            mEvalHandler.sendStopCloseCountDown()

            mEvalView?.setProgress(msg)
        }

        override fun recordOfByte(data: ByteArray?, begin: Int, end: Int, decibel: Double) {
//            if (BuildConfig.DEBUG) {
//                Log.d(TAG, "decibel=$decibel")
//            }
        }

        override fun onRecordFile(filePath: String?) {
            mRecordPath = filePath
            mEvalView?.recordEnd()
            mEvalListeners.map { listener ->
                listener.onRecordFile(mRecordPath)
            }
        }

        override fun onEvalResult(result: String?, evalSDKEntity: EvalSDKEntity?) {
            val parseResult =
                YDResultParse.parseResult(result, evalSDKEntity?.type ?: EvalType.ZH_CHS)
            val score = parseResult[0] as Double

            val evalEntity = evalSDKEntity as EvalEntity
            if (evalEntity.scoreSound) {
                playResultAudio(score)
            }
            var text = parseResult[1] as SpannableStringBuilder?
            if (text.isNullOrBlank()) {
                text = mEvalView?.mContent
                if (text.isNullOrBlank()) {
                    text = YDResultParse.getLowSpan(
                        EvalSDK.getCurrEntity()?.content ?: ""
                    )
                }
            }
            mEvalView?.showResult(text, score)

            var currEntity: EvalEntity? = null
            if (EvalSDK.getCurrEntity() is EvalEntity) {
                currEntity = EvalSDK.getCurrEntity() as EvalEntity
            }

            mEvalHandler.sendCloseCountDown()
            mEvalListeners.map { listener ->
                listener.onEvalResult(score, text, result, currEntity)
            }
        }

        override fun onTimeOut() {
            EvalSDK.cancelEval()
            mEvalView?.showError("评测超时，请重新评测哦！")
        }


    }

    /**
     * 取消评测
     */
    fun cancelEval() {
        NLogger.d(TAG, "调用取消评测 cancelEval")
        cancelAll()
        dismiss()
    }

    private fun cancelAll() {
        NLogger.d(TAG, "调用取消全部 cancelAll")
        mEvalHandler.removeCallbacksAndMessages(null)
        EvalSDK.cancelEval()
        NttPlayCtrl.stop()
    }

    /**
     * 初始化弹窗属性
     */
    private fun initLayoutParams() {
        mWindowLayoutParams = WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                    or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                    or WindowManager.LayoutParams.FLAG_FULLSCREEN
                    or WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER,
            PixelFormat.TRANSLUCENT
        )
        mWindowLayoutParams.softInputMode =
            WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
    }


    /**
     * 初始化评测view
     */
    private fun initView() {
        mContext.let {
            NLogger.d(TAG, "初始化评测view")
            mEvalView = EvalView(it!!)
            mEvalView?.addOnAttachStateChangeListener(this)
            mEvalView?.mListener = object : IEvalViewListener {
                override fun clickClose() {
                    mEvalListeners.map { listener ->
                        listener.onClose(false)
                    }
                    dismiss()
                }

                override fun clickStopEval() {
                    EvalSDK.stopRecord()
                }

                override fun clickAgain() {
                    startEval(EvalSDK.getCurrEntity() as EvalEntity)
                }

                //播放录音
                override fun clickRecord() {
                    if (!mRecordPath.isNullOrBlank()) {
                        val audioItem = AudioItem(mRecordPath, SourceType.SOURCE_TYPE_FILE)
                        playAudio(audioItem, 1)
                    } else {
                        ToastUtils.showShort("录音丢失，请重新评测哦")
                    }
                }

                override fun clickOriginal() {
                    val entity = EvalSDK.getCurrEntity()
                    if (entity is EvalEntity && !entity.audioUrl.isNullOrBlank()) {
                        val audioItem = AudioItem(
                            entity.audioUrl,
                            startPoint = entity.audioStart,
                            endPoint = entity.audioEnd,
                            speed = entity.speed
                        )
                        playAudio(audioItem, 2)
                    } else {
                        ToastUtils.showShort("没有音频哦！")
                    }
                }

                override fun clickPre() {
                    mEvalListeners.map { listener ->
                        listener.onClickPre()
                    }
                }

                override fun clickNext() {
                    mEvalListeners.map { listener ->
                        listener.onClickNext()
                    }
                }
            }
        }
    }

    /**
     * 显示
     */
    private fun show(entity: EvalEntity?, notStarted: Boolean) {
        NLogger.d(TAG, "小听弹窗显示")
        if (mWindowManager == null) {
            mWindowManager = mContext?.getSystemService(Service.WINDOW_SERVICE) as WindowManager
        }
        if (mEvalView == null) {
            NLogger.d(TAG, "第一次显示，view为空")
            initView()
        }
        mEvalView?.let {
            if (mEvalView?.isAttachedToWindow != true) {
                mWindowManager?.addView(it, mWindowLayoutParams)
            } else {//重新设置mWindowLayoutParams，是为了唤醒屏幕
                it.layoutParams = mWindowLayoutParams
            }
            if (notStarted) {
                it.beforeEval(entity)
            } else {
                it.startEval(entity)
            }
        }
    }

    /**
     * 消失
     */
    private fun dismiss() {
        NLogger.d(TAG, "评测弹窗消失")
        try {
            if (mEvalView?.isAttachedToWindow == true) {
                mWindowManager?.removeViewImmediate(mEvalView)
            }
        } catch (e: Exception) {
            NLogger.d(TAG, "评测弹窗消失异常", e.message)
        }
    }

    override fun onViewAttachedToWindow(v: View?) {
        try {
            NLogger.d(TAG, "评测弹窗起来了，请讲话！")
            mEvalListeners.map { listener ->
                listener.onShow()
            }
        } catch (e: Exception) {
            NLogger.d(TAG, "评测弹窗起来了，出现异常", e.message)
        }
    }

    override fun onViewDetachedFromWindow(v: View?) {
        try {
            EvalSDK.unRegisterEvalListener(mEvalSDKListener)
            mEvalStatus = EvalStatus.UNKNOW
            NLogger.d(TAG, "评测弹窗隐藏了！")
            cancelEval()
            mEvalListeners.map { listener ->
                listener.onDismiss()
            }
        } catch (e: Exception) {
            NLogger.d(TAG, "评测弹窗隐藏了，出现异常，", e.message)
        }

    }

    /**
     * 播放结果音效
     */
    private fun playResultAudio(score: Double) {
        val fileName = when {
            score >= EvalScore.STAR_FIVE -> {
                "eval/eval_star_five.mp3"
            }
            score >= EvalScore.STAR_FOUR -> {
                "eval/eval_star_three.mp3"
            }
            score >= EvalScore.STAR_THREE -> {
                "eval/eval_star_three.mp3"
            }
            score >= EvalScore.STAR_TWO -> {
                "eval/eval_star_one.mp3"
            }
            score >= EvalScore.STAR_ONE -> {
                "eval/eval_star_one.mp3"
            }
            else -> {
                "eval/eval_star_fail.mp3"
            }
        }
        val audioItem = AudioItem(fileName, SourceType.SOURCE_TYPE_ASSETS)
        playAudio(audioItem, 0)
    }


    private fun playAudio(audioItem: AudioItem, type: Int) {
        playAudio(audioItem, type, false)
    }

    /**
     * 播放音频
     *  @param audioItem 音频数据
     *  @param type 0分数音效、1录音、2原音
     *  @param notStarted 还未评测前播放原音
     */
    private fun playAudio(audioItem: AudioItem, type: Int, notStarted: Boolean) {
        NLogger.d(TAG, "播放音频！", GsonUtils.toJson(audioItem), "type=$type")
        if (type == 1) {
            mEvalHandler.sendPlayRecord()
        } else if (type == 2) {
            mEvalHandler.sendPlayOriginal(notStarted)
        }
        NttPlayCtrl.setPlayAudioListener(object : IAudioPlayListener {

            fun onComplete() {
                if (type == 1) {
                    mEvalHandler.sendStopPlayRecord()
                } else if (type == 2) {
                    mEvalHandler.sendStopPlayOriginal(notStarted)
                }
            }

            override fun onPrepare(url: String?, id: Long) {
                NLogger.d(
                    TAG, "准备播放音频",
                    "url=$url",
                    "id=$id"
                )
            }

            override fun onComplete(url: String?, id: Long) {
                NttPlayCtrl.setPlayAudioListener(null)
                NLogger.d(
                    TAG, "播放音频完成",
                    "url=$url",
                    "id=$id"
                )
                onComplete()
            }

            override fun onError(url: String?, id: Long, code: Int, msg: String?) {
                NttPlayCtrl.setPlayAudioListener(null)
                NLogger.d(
                    TAG, "播放音频异常！",
                    "url=$url",
                    "id=$id",
                    "code=$code",
                    "msg=$msg",
                )
                if (notStarted) {
                    mEvalSDKListener.onError("播放音频异常！", EvalError.ERROR_2)
                } else {
                    onComplete()
                }
            }

            override fun onStop(url: String?, id: Long) {
                super.onStop(url, id)
                NttPlayCtrl.setPlayAudioListener(null)
                NLogger.d(
                    TAG, "播放音频暂停！onStop",
                    "url=$url",
                    "id=$id",
                )
                if (notStarted) {
                    mEvalSDKListener.onError("播放音频异常！", EvalError.ERROR_2)
                } else {
                    onComplete()
                }
            }

            override fun onPause() {
                super.onPause()
                NttPlayCtrl.setPlayAudioListener(null)
                NLogger.d(
                    TAG, "播放音频暂停！onPause",
                )
                if (notStarted) {
                    mEvalSDKListener.onError("播放音频异常！", EvalError.ERROR_2)
                } else {
                    onComplete()
                }
            }

//            override fun onSoundEffect(enable: Boolean, sessionId: Int) {
//
//            }
//
//            override fun onReleaseSoundEffect(sessionId: Int) {
//
//            }

        })
        NttPlayCtrl.playAudio(audioItem)
    }

    private val mEvalHandler: EvalHandler = EvalHandler(Looper.getMainLooper()) { msg ->
        when (msg.what) {
            EvalWhat.BEFORE_ORIGIN -> {
                NLogger.d(TAG, "EvalHandler 事先播放原音")

                val entity = msg.obj as EvalEntity

                show(entity, true)
                val audioItem = AudioItem(
                    entity.audioUrl,
                    startPoint = entity.audioStart,
                    endPoint = entity.audioEnd,
                    speed = entity.speed
                )
                playAudio(audioItem, 2, true)
            }
            EvalWhat.PLAY_RECORD -> {
                NLogger.d(TAG, "EvalHandler 播放录音")
                mEvalView?.playRecord()
            }
            EvalWhat.PLAY_ORIGINAL -> {
                NLogger.d(TAG, "EvalHandler 播放原音")
                if (msg.arg1 == 0) {//评测完播放原音
                    mEvalView?.playOriginal()
                }
            }
            EvalWhat.STOP_PLAY_ORIGINAL -> {
                NLogger.d(TAG, "EvalHandler 播放原音暂停")
                if (msg.arg1 == 0) {//评测完播放原音
                    mEvalView?.stopPlayOriginal()
                } else {
                    EvalSDK.startEval(mEvalView?.mEvalEntity)
                }
            }
            EvalWhat.STOP_PLAY_RECORD -> {
                NLogger.d(TAG, "EvalHandler 播放录音暂停")
                mEvalView?.stopPlayRecord()
            }
            EvalWhat.CLOSE_COUNTDOWN -> {
                NLogger.d(TAG, "EvalHandler 自动关闭生效")
                mEvalListeners.map { listener ->
                    listener.onClose(true)
                }
                dismiss()
            }
        }
        true
    }

}